/**
 * 
 */
package cn.edu.nju.ws.sview.wyge.relations.adataset.relations.qxliu.relation;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;

import com.hp.hpl.jena.vocabulary.RDF;

import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.database.DBConnectionFactory;

/**
 * @author Weiyi Ge (geweiyi@gmail.com) 2012-8-27
 * 
 */
public class ExpandFromTwoVariables {
	ArrayList<String[]> patterns = null;
	ArrayList<ArrayList<String>> results = null;
	ArrayList<ArrayList<String>> triples = null;// triples from dataset
	String vi = null;
	String vj = null;
	String docs = "";
	public ExpandFromTwoVariables(ArrayList<String[]> patterns, ArrayList<Integer> doc_id){
		this.patterns = patterns;
		RelationEvaluation re = new RelationEvaluation();
		this.results = re.getValuesFromPatterns(patterns, doc_id);

		StringBuffer sqlpart = new StringBuffer();
		for (Integer id : doc_id) {
			sqlpart.append(id + ",");
		}
		if (sqlpart.length() > 0) {
			sqlpart.deleteCharAt(sqlpart.lastIndexOf(","));
		}
		this.docs = sqlpart.toString();
	}
	public ArrayList<ArrayList<String>> expandOnType(String v) {
		int idx_v = results.get(0).indexOf(v);
		HashSet<String> constants = new HashSet<String>();
		for (int line = 1; line < results.size(); line++) {
			ArrayList<String> row = results.get(line);
			String cp = row.get(idx_v);
			constants.add(cp);
		}
		HashSet<String> allRels = getDirectTypeRelations(constants);
		HashSet<String> existRels = getExistTypeRelations(constants,v);
		return getTypeExpands(v, allRels, existRels);
	}
//	public ArrayList<ArrayList<String>> expand(ArrayList<String[]> patterns, ArrayList<Integer> doc_id, String vi, String vj) {
	public ArrayList<ArrayList<String>> expand(String vi, String vj) {
		/*this.patterns = patterns;
		RelationEvaluation re = new RelationEvaluation();
		this.results = re.getValuesFromPatterns(patterns, doc_id);

		StringBuffer sqlpart = new StringBuffer();
		for (Integer id : doc_id) {
			sqlpart.append(id + ",");
		}
		if (sqlpart.length() > 0) {
			sqlpart.deleteCharAt(sqlpart.lastIndexOf(","));
		}
		docs = sqlpart.toString();*/

		if (this.triples == null) {
			this.getTriples();
		}
		this.vi = vi;
		this.vj = vj;
		int idx_vi = results.get(0).indexOf(vi);
		int idx_vj = results.get(0).indexOf(vj);
		HashSet<ConstantPair> constants = new HashSet<ConstantPair>();
		for (int line = 1; line < results.size(); line++) {
			ArrayList<String> row = results.get(line);
			ConstantPair cp = new ConstantPair(row.get(idx_vi), row.get(idx_vj));
			constants.add(cp);
		}
		HashSet<String> allRels = getDirectRelations(constants);
		HashSet<String> existRels = getExistRelations(constants);
		return getExpands(allRels, existRels);
	}
	
	private HashSet<String> getExistTypeRelations(HashSet<String> constants, String v){
		HashSet<String> res = new HashSet<String>();
		try {
			String typep = "u"+URIIDCache.getInstance().getURIID(RDF.type.getURI(), false);
			for(String[] pat : patterns){
				String s = pat[0];
				String p = pat[1];
				String o = pat[2];
				if(s.contentEquals(v) && p.contentEquals(typep)){
					res.add(o);
				}
			}
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return res;
	}
	private HashSet<String> getExistRelations(HashSet<ConstantPair> constants) {
		HashSet<String> res = new HashSet<String>();
		for (String[] pat : patterns) {
			String s = pat[0];
			String p = pat[1];
			String o = pat[2];
			if (s.equals(vi) && o.equals(vj)) {
				res.add(p);
			}
		}
		return res;
	}
	private ArrayList<ArrayList<String>> getTypeExpands(String v, HashSet<String> allRels, HashSet<String> existRels){
		ArrayList<ArrayList<String>> expandPatterns = new ArrayList<ArrayList<String>>();
		try {
			String typep = "u"+RDF.type.getURI();
			for (String class_obj : allRels) {
				if (!existRels.contains(class_obj)) {
					ArrayList<String> expand = new ArrayList<String>();
					expand.add(v);
					expand.add(typep);
					expand.add(class_obj);
					expandPatterns.add(expand);
				}
			}
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return expandPatterns;
	}
	private ArrayList<ArrayList<String>> getExpands(HashSet<String> allRels,
			HashSet<String> existRels) {
		ArrayList<ArrayList<String>> expandPatterns = new ArrayList<ArrayList<String>>();
		for (String rel : allRels) {
			if (!existRels.contains(rel)) {
				ArrayList<String> expand = new ArrayList<String>();
				expand.add(vi);
				expand.add(rel);
				expand.add(vj);
				expandPatterns.add(expand);
			}
		}
		return expandPatterns;
	}
	private HashSet<String> getDirectTypeRelations(HashSet<String> constants){
		HashSet<String> res = new HashSet<String>();
		try {
			Connection conn = DBConnectionFactory.getConnection();
			PreparedStatement selps = conn
					.prepareStatement("SELECT distinct o FROM quadruple where s = ? and p = ? and doc_id in (?)");
			HashSet<String> types = new HashSet<String>();
			for (String c : constants) {
				String s_id = c;
				if (c.startsWith("u")) {
					int tmp = URIIDCache.getInstance().getURIID(c.substring(1), false);
					s_id = "u" + tmp;
				} else if (c.startsWith("_:IN<")) {
					int bndid = Integer
							.valueOf(c.substring(5, c.indexOf(">NO")));
					int bnid = Integer
							.valueOf(c.substring(c.indexOf(">NO") + 3));
					s_id = "b" + bndid + ":" + bnid;
				}
				String p_id = "u"+URIIDCache.getInstance().getURIID(RDF.type.getURI(), false);
				
				selps.setString(1, s_id);
				selps.setString(2, p_id);
				selps.setString(3, docs);
				ResultSet selrs = selps.executeQuery();
				while (selrs.next()) {
					types.add(selrs.getString(1));
				}
				selrs.close();
			}
			for (String c : types) {
				int class_id = Integer.valueOf(c.substring(1));
				res.add("u" + URIIDCache.getInstance().getURI(class_id));
			}
			selps.close();
			conn.close();
		} catch (Throwable t) {
			t.printStackTrace();
		}
		return res;
	}
	private HashSet<String> getDirectRelations(HashSet<ConstantPair> constants) {
		Connection conn = DBConnectionFactory.getConnection();
		HashSet<String> res = new HashSet<String>();
		try {
			PreparedStatement selps = conn
					.prepareStatement("SELECT distinct p FROM quadruple where s = ? and o = ? and doc_id in (?)");
			HashSet<String> props = new HashSet<String>();
			for (ConstantPair cp : constants) {
				String i = cp.getConstantI();
				String j = cp.getConstantJ();
				String s_id = i;
				String o_id = j;
				if (i.startsWith("u")) {
					int tmp = URIIDCache.getInstance().getURIID(i.substring(1),
							false);
					s_id = "u" + tmp;
				} else if (i.startsWith("_:IN<")) {
					int bndid = Integer
							.valueOf(i.substring(5, i.indexOf(">NO")));
					int bnid = Integer
							.valueOf(i.substring(i.indexOf(">NO") + 3));
					s_id = "b" + bndid + ":" + bnid;
				}
				if (j.startsWith("u")) {
					int tmp = URIIDCache.getInstance().getURIID(j.substring(1),
							false);
					o_id = "u" + tmp;
				} else if (j.startsWith("_:IN<")) {
					int bndid = Integer
							.valueOf(j.substring(5, j.indexOf(">NO")));
					int bnid = Integer
							.valueOf(j.substring(j.indexOf(">NO") + 3));
					o_id = "b" + bndid + ":" + bnid;
				}

				selps.setString(1, s_id);
				selps.setString(2, o_id);
				selps.setString(3, docs);
				ResultSet selrs = selps.executeQuery();
				while (selrs.next()) {
					props.add(selrs.getString(1));
				}
				selrs.close();
			}
			for (String prop : props) {
				int prop_id = Integer.valueOf(prop.substring(1));
				res.add("u" + URIIDCache.getInstance().getURI(prop_id));
			}
			selps.close();
			conn.close();
		} catch (Throwable t) {
			t.printStackTrace();
		}
		return res;
	}

	private ArrayList<ArrayList<String>> getTriples() {
		try {
			Connection fconn = DBConnectionFactory.getConnection();//
			PreparedStatement pstmt = fconn
					.prepareStatement("select s,p,o from quadruple where doc_id in ("
							+ docs + ");");
			ResultSet rs = pstmt.executeQuery();
			this.triples = new ArrayList<ArrayList<String>>();
			ArrayList<String> row = null;
			while (rs.next()) {
				row = new ArrayList<String>();
				for (int i = 1; i <= 3; i++) {
					if (rs.getString(i).startsWith("u")) {// if uri
						int s_id = Integer
								.valueOf(rs.getString(i).substring(1));
						row.add("u" + URIIDCache.getInstance().getURI(s_id));
					} else if (rs.getString(i).startsWith("b")) {
						String nbstr = rs.getString(i);// e.g. b322960:5
						int bndid = Integer.valueOf(nbstr.substring(1,
								nbstr.indexOf(":")));// get doc id of blanknode
						int bnid = Integer.valueOf(nbstr.substring(nbstr
								.indexOf(":") + 1));
						String bn = "_:IN<"
								+ URIIDCache.getInstance().getURI(bndid)
								+ ">NO" + bnid;
						row.add(bn);
					} else {// if literal
						row.add(rs.getString(i));
					}
				}
				this.triples.add(row);
			}
			rs.close();
			pstmt.close();
			fconn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return this.triples;
	}

}
